package com.questionnaires.controller;

import com.questionnaires.exception.NotExistsException;
import com.questionnaires.exception.NotUniqueException;
import com.questionnaires.model.User;
import com.questionnaires.service.UserService;
import com.questionnaires.utils.UserUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import javax.validation.Valid;
import java.util.Map;

/**
 * Controller for handling user operations.
 *
 * @author ioana.ruca@gmail.com
 */
@Controller
public class UserController {

    @Autowired
    private UserService userService;


    public static final String REDIRECT_ADMIN = "redirect:/admin";
    public static final String VIEW_ADMIN = "admin/home";
    public static final String REDIRECT_MANAGER = "redirect:/manager";
    public static final String VIEW_MANAGER = "manager/home";
    public static final String REDIRECT_INDEX = "redirect:/index";

    /**
     * Username not unique error message key.
     */
    private static final String USERNAME_NOT_UNIQUE = "NotUnique.user.username";

    /**
     * User deleted successfully.
     */
    private static final String USER_DELETED = "Deleted.user.success";

    /**
     * User not exists error message key.
     */
    private static final String USER_NOT_EXISTS = "NotExists.user";

    /**
     * All users view.
     */
    public static final String USERS_VIEW = "user/users";

    /**
     * Redirect to users handler mapping.
     */
    public static final String REDIRECT_USERS = "redirect:/users";

    @RequestMapping(value = "/admin", method = RequestMethod.GET)
    public String viewAdmin(HttpSession session) {

        User user = (User)session.getAttribute("user");
        if (user == null || !user.checkUserAdmin() )
            return UserController.REDIRECT_INDEX;
        return VIEW_ADMIN;
    }

    @RequestMapping(value = "/manager", method = RequestMethod.GET)
    public String viewManager(HttpSession session) {

        User user = (User)session.getAttribute("user");
        if (user == null || !user.checkUserManager() )
            return UserController.REDIRECT_INDEX;
        return VIEW_MANAGER;
    }

    /**
     * Prepares and retrieves the all users view.
     *
     * @param modelMap the current page model map
     * @return the all users view
     */
    @RequestMapping(value = "/users")
    public String viewAllUsers(Map<String, Object> modelMap, HttpSession session) {

        User loggedUser = (User)session.getAttribute("user");
        if (loggedUser == null || !loggedUser.checkUserAdmin() )
            return UserController.REDIRECT_INDEX;
        modelMap.put("usersList", userService.findAll());
        User user = new User();
        modelMap.put("user", user);
        return USERS_VIEW;
    }

    /**
     * Performs the request of adding a new user.
     *
     * @param user   the user to be added
     * @param result the spring form binding result.
     * @return the all users view in case of success ot the add user view displaying existing errors
     */
    @RequestMapping(value = "/addUser", method = RequestMethod.POST)
    public String addUser(@ModelAttribute("user")
                          @Valid User user, BindingResult result, HttpSession session) {

        User loggedUser = (User)session.getAttribute("user");
        if (loggedUser == null || !loggedUser.checkUserAdmin() )
            return UserController.REDIRECT_INDEX;
        if (result.hasErrors()) {
            return USERS_VIEW;//ADD_USER_VIEW;
        }
        try {
            userService.saveOrUpdate(user);
        } catch (NotUniqueException e) {
            //log
            result.rejectValue("username", USERNAME_NOT_UNIQUE);
            return USERS_VIEW;//ADD_USER_VIEW;
        }
        return "redirect:/users";
    }

    @RequestMapping(value = "/users/delete", method = RequestMethod.POST)
    public ModelAndView deleteUser(HttpServletRequest request, HttpSession session) {

        User user = (User)session.getAttribute("user");
        if (user == null || !user.checkUserAdmin() )
            return new ModelAndView(UserController.REDIRECT_INDEX);
        ModelAndView modelAndView = new ModelAndView(REDIRECT_USERS);
        long userId = Long.parseLong(request.getParameter("userId"));
        try {
            userService.deleteById(userId);
        } catch (NotExistsException e) {
            //log
            modelAndView.addObject("errorMessage", USER_NOT_EXISTS);
            return modelAndView;
        }
        modelAndView.addObject("successMessage", USER_DELETED);
        return modelAndView;
    }

    @RequestMapping(value = "/logout")
    public String logout(HttpServletRequest request) {

        request.getSession().invalidate();
        return REDIRECT_INDEX;
    }
    
    @RequestMapping(value = "/login", method = RequestMethod.POST)
    public String login(HttpServletRequest request, Map<String, Object> modelMap, HttpSession session) {
        String username = request.getParameter("user");
        String password = request.getParameter("password");      
        if (username == null || "".equals(username) || password == null || "".equals(password)) {
            modelMap.put("error", "Username and password cannot be null.");
            return "index";
        }
        User user = userService.findByName(username);
        if (user== null || !user.getPassword().equals(UserUtils.encode(password))) {
            modelMap.put("error", "User or password incorrect");
            return "index";
        }
        session.setAttribute("user", user);
        if(user.checkUserAdmin()) {
            return REDIRECT_ADMIN;
        }
        if(user.checkUserManager()) {
            return REDIRECT_MANAGER;
        }
        return null;
    }

}
